pub fn convert_base(num_str: &str, to_base: u32) -> String {
    let (num, from_base) = parse_src(num_str);
    let dec = to_dec(num, from_base);
    from_dec(dec, to_base)
}

fn parse_src(num_str: &str) -> (&str, u32) {
    let lp = num_str.as_bytes().iter().position(|c| *c == b'(').unwrap();
    (
        &num_str[..lp],
        num_str[lp + 1..num_str.len() - 1].parse().unwrap(),
    )
}

fn to_dec(num: &str, base: u32) -> i32 {
    let neg = if num.starts_with('-') { 1 } else { 0 };
    let char_index = |c| CHARS.chars().position(|x| x == c).unwrap() as i32;
    num[neg..].chars()
        .rev()
        .enumerate()
        .fold(0, |acc, (idx, c)| {
            acc + base.pow(idx as u32) as i32 * char_index(c)
    }) * [1, -1][neg]
}

const CHARS: &str = "0123456789abcdef";

fn from_dec(mut num: i32, base: u32) -> String {
    if num == 0 {
        return "0".to_string();
    }
    let mut result = String::new();
    let neg = num.is_negative();
    num = num.abs();
    while num > 0 {
        let reminder = CHARS.chars().nth((num % base as i32) as usize).unwrap();
        result.push(reminder);
        num /= base as i32;
    }
    if neg {
        result.push('-');
    }
    result.chars().rev().collect()
}
